/* $Id: VBoxMPWddm.h $ */
/** @file
 * VBox WDDM Miniport driver
 */

/*
 * Copyright (C) 2011-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */

#ifndef _WDDM_INCLUDE_VBOXMPWDDM_H_
#define _WDDM_INCLUDE_VBOXMPWDDM_H_

#include <ntddk.h>

extern "C" {
#include <dispmprt.h>
}

#include "common/VBoxMPIf.h"
#include "common/VBoxMPDevExt.h"
#include "gallium/VBoxMPGaWddm.h"

#define VBOXWDDM_DEFAULT_REFRESH_RATE 60
#define VBOXWDDM_DECODER_REFRESH_RATE 120

extern volatile DWORD g_RefreshRate;

#define VBOXWDDM_IS_DISPLAYONLY() (g_VBoxDisplayOnly)

#define VBOX_WDDM_DRIVERNAME L"VBoxWddm"

#define VBOXWDDM_CFG_DRV_DEFAULT                        0
#define VBOXWDDM_CFG_DRV_SECONDARY_TARGETS_CONNECTED    1

#define VBOXWDDM_CFG_DRVTARGET_CONNECTED                1

PVOID vboxWddmMemAlloc(IN SIZE_T cbSize);
PVOID vboxWddmMemAllocZero(IN SIZE_T cbSize);
VOID vboxWddmMemFree(PVOID pvMem);

DECLINLINE(BOOLEAN) vboxWddmAddrSetVram(PVBOXWDDM_ADDR pAddr, UINT SegmentId, VBOXVIDEOOFFSET offVram)
{
    if (pAddr->SegmentId == SegmentId && pAddr->offVram == offVram)
        return FALSE;

    pAddr->SegmentId = SegmentId;
    pAddr->offVram = offVram;
    return TRUE;
}

DECLINLINE(bool) vboxWddmAddrVramEqual(const VBOXWDDM_ADDR *pAddr1, const VBOXWDDM_ADDR *pAddr2)
{
    return pAddr1->SegmentId == pAddr2->SegmentId && pAddr1->offVram == pAddr2->offVram;
}

DECLINLINE(VOID) vboxWddmAssignPrimary(PVBOXWDDM_SOURCE pSource, PVBOXWDDM_ALLOCATION pAllocation,
                                       D3DDDI_VIDEO_PRESENT_SOURCE_ID srcId)
{
    RT_NOREF(srcId);

    /* vboxWddmAssignPrimary can not be run in reentrant order,
     * so safely do a direct unlocked check here
     */
    if (pSource->pPrimaryAllocation == pAllocation) {
        return;
    }

    if (pSource->pPrimaryAllocation) {
        PVBOXWDDM_ALLOCATION pOldAlloc = pSource->pPrimaryAllocation;
        /* clear the visibility info fo the current primary */
        pOldAlloc->bVisible = FALSE;
        pOldAlloc->bAssigned = FALSE;
        Assert(pOldAlloc->AllocData.SurfDesc.VidPnSourceId == srcId);
        pOldAlloc->CurVidPnSourceId = -1;
    }

    if (pAllocation) {
        Assert(pAllocation->AllocData.SurfDesc.VidPnSourceId == srcId);
        pAllocation->bAssigned = TRUE;
        pAllocation->bVisible = pSource->bVisible;
        pAllocation->CurVidPnSourceId = srcId;

        if (pSource->AllocData.hostID != pAllocation->AllocData.hostID) {
            pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */
            pSource->AllocData.hostID = pAllocation->AllocData.hostID;
        }

        if (!vboxWddmAddrVramEqual(&pSource->AllocData.Addr, &pAllocation->AllocData.Addr)) {
            if (!pAllocation->AllocData.hostID) {
                pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */
            }

            pSource->AllocData.Addr = pAllocation->AllocData.Addr;
        }
    } else {
        pSource->u8SyncState &= ~VBOXWDDM_HGSYNC_F_SYNCED_LOCATION; /* force guest->host notification */
        /* ensure we do not refer to the deleted host id */
        pSource->AllocData.hostID = 0;
    }

    KIRQL OldIrql;
    KeAcquireSpinLock(&pSource->AllocationLock, &OldIrql);
    pSource->pPrimaryAllocation = pAllocation;
    KeReleaseSpinLock(&pSource->AllocationLock, OldIrql);
}

DECLINLINE(VBOXVIDEOOFFSET) vboxWddmVramAddrToOffset(PVBOXMP_DEVEXT pDevExt,
                                                     PHYSICAL_ADDRESS Addr)
{
    PVBOXMP_COMMON pCommon = VBoxCommonFromDeviceExt(pDevExt);
    return (VBOXVIDEOOFFSET)Addr.QuadPart - pCommon->phVRAM.QuadPart;
}

BOOLEAN GetCurrentProcessName(PUNICODE_STRING* pImageFileName);

#endif
